{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Direct inference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# example of inference for direct submission\n",
    "!cd GWC_YOLO && python detect.py --img-size 800 --name fold{index} --weights ../{name}/fold{index}.pt --source ../test --augment --nosave --save-csv --conf-thres 0.50"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ensemble using weighted boxes fusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Put the folders containing labels txt files in the current directory. Each txt file contains *cls, xywh, conf*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# example of inference for ensemble\n",
    "!cd GWC_YOLO && python detect.py --img-size 800 --name fold{index} --weights ../{name}/fold{index}.pt --source ../test --augment --nosave --save-txt --save-conf --conf-thres 0.50\n",
    "!mv GWC_YOLO/runs/detect/fold{index}/labels fold{index}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "executionInfo": {
     "elapsed": 348,
     "status": "ok",
     "timestamp": 1625464630398,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "WLt8CKU9bXTE"
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import pandas as pd\n",
    "\n",
    "# Put the names of the folders here\n",
    "folders = ['fold1', 'fold3', 'fold3']\n",
    "# Put the weights attached to each folder here\n",
    "weights_list = [1, 1, 1]\n",
    "# Put the indexes of the weights whose confidences should be *sqrt*ed here\n",
    "# This is especially useful when ensembling models predicted using *master* branch and *original* branch\n",
    "sqrt_indexes = [2]\n",
    "files = [os.listdir(folder) for folder in folders]\n",
    "submission = pd.read_csv('submission.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 11077,
     "status": "ok",
     "timestamp": 1625464537675,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "psxJC7EC_5TX",
    "outputId": "ad9a526f-215b-4b45-8e7f-c9b42bd80c06"
   },
   "outputs": [],
   "source": [
    "!pip install aicrowd-cli\n",
    "!pip install ensemble_boxes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "executionInfo": {
     "elapsed": 2,
     "status": "ok",
     "timestamp": 1625464633666,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "nPMiFmHmW_iT"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "def parse_box(box):\n",
    "  x, y, w, h = box\n",
    "  return max(0, x - w / 2), max(0, y - h / 2), min(1, x + w / 2), min(1, y + h / 2)\n",
    "\n",
    "def normalize(boxes):\n",
    "  return [[entry / 1024 for entry in box] for box in boxes]\n",
    "\n",
    "def de_normalize(boxes):\n",
    "  return [[entry * 1024 for entry in box] for box in boxes]\n",
    "\n",
    "def parse_file(file_name, current):\n",
    "  boxes = []\n",
    "  scores = []\n",
    "  labels = []\n",
    "  with open(file_name) as f:\n",
    "    for line in f:\n",
    "      cls, *xywh, conf = list(map(float, line.split()))\n",
    "      boxes.append(parse_box(xywh))\n",
    "      if current in sqrt_indexes:\n",
    "        scores.append(np.sqrt(conf))\n",
    "      else:\n",
    "        scores.append(conf)\n",
    "      labels.append(0)\n",
    "  return boxes, scores, labels\n",
    "\n",
    "def encodeBoxes(boxes, scores, score_thr=0.0):\n",
    "  strboxes = \";\".join([\" \".join([str(round(i)) for i in box]) for (box, score) in zip(boxes, scores) if score > score_thr])\n",
    "\n",
    "  if len(strboxes) == 0:\n",
    "    strboxes = \"no_box\"\n",
    "  \n",
    "  return strboxes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 216
    },
    "executionInfo": {
     "elapsed": 46888,
     "status": "ok",
     "timestamp": 1625464683094,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "7r7nLBJhjBB0",
    "outputId": "646d6561-0880-4acd-acee-0865ee52466e"
   },
   "outputs": [],
   "source": [
    "from ensemble_boxes import weighted_boxes_fusion\n",
    "from tqdm import tqdm\n",
    "import os, shutil\n",
    "\n",
    "\n",
    "for index, line in tqdm(enumerate(submission.iterrows())):\n",
    "  img_name = line[1]['image_name']\n",
    "  txt_name = img_name + '.txt'\n",
    "  boxes_list = [[] for _ in range(len(folders))]\n",
    "  scores_list = [[] for _ in range(len(folders))]\n",
    "  labels_list = [[] for _ in range(len(folders))]\n",
    "  for current, folder in enumerate(folders):\n",
    "    # assert txt_name in files[current]\n",
    "    boxes, scores, labels = parse_file(os.path.join(folder, txt_name), current)\n",
    "    boxes_list[current] = boxes\n",
    "    scores_list[current] = scores\n",
    "    labels_list[current] = labels\n",
    "  final_boxes, final_scores, _ = weighted_boxes_fusion(boxes_list, scores_list, labels_list, weights=weights_list)\n",
    "\n",
    "  submission.at[index, 'PredString'] = encodeBoxes(de_normalize(final_boxes), final_scores)\n",
    "\n",
    "submission.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "executionInfo": {
     "elapsed": 7,
     "status": "ok",
     "timestamp": 1625464683096,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "RYO7PyAgTLve"
   },
   "outputs": [],
   "source": [
    "submission.to_csv('ensemble.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 595
    },
    "executionInfo": {
     "elapsed": 6314,
     "status": "ok",
     "timestamp": 1625419543672,
     "user": {
      "displayName": "Martinez Stark",
      "photoUrl": "",
      "userId": "15125435938317481871"
     },
     "user_tz": -480
    },
    "id": "AG8zYBT2SX9i",
    "outputId": "37c0b88a-ecc0-46d9-c388-ee089cc2b98d"
   },
   "outputs": [],
   "source": [
    "# For sanity check\n",
    "!cp drive/MyDrive/GWC_data/test.zip ./\n",
    "!unzip test.zip\n",
    "\n",
    "import pandas as pd\n",
    "ensemble = pd.read_csv('ensemble.csv')\n",
    "image_name = ensemble['image_name'].tolist()[0]\n",
    "boxes = ensemble['PredString'].tolist()[0]\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import cv2\n",
    "%matplotlib inline\n",
    "\n",
    "def visualize(image_path, boxes):\n",
    "  boxes = [box.split(' ') for box in boxes.split(';')]\n",
    "  image = cv2.imread(image_path)\n",
    "  for (x1, y1, x2, y2) in boxes:\n",
    "    cv2.rectangle(image,(int(x1),int(y1)),(int(x2),int(y2)),(255,0,0),5)\n",
    "  plt.rcParams[\"figure.figsize\"] = (10, 10)\n",
    "  plt.imshow(image[...,::-1])\n",
    "\n",
    "visualize(f'test/{image_name}.png', boxes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5IX79Ffa_5Te"
   },
   "source": [
    "## Making Direct Submission thought Aicrowd CLI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 5855,
     "status": "ok",
     "timestamp": 1625464699787,
     "user": {
      "displayName": "Percy Chen",
      "photoUrl": "",
      "userId": "01195213417322727822"
     },
     "user_tz": -480
    },
    "id": "2Ewdrf4wYjQO",
    "outputId": "35abc220-a9c8-433b-9c18-011a514b936c"
   },
   "outputs": [],
   "source": [
    "### Please enter your API Key from [here](https://www.aicrowd.com/participants/me).\n",
    "API_KEY = \"api_key\" \n",
    "!aicrowd login --api-key $API_KEY\n",
    "!aicrowd submission create -c global-wheat-challenge-2021 -f ensemble.csv"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "Weighted Boxes Fusion_final.ipynb",
   "provenance": [
    {
     "file_id": "https://gist.github.com/aicrowd-bot/b2bf6af7d4e7ed84c7910f9240430b42",
     "timestamp": 1622545790641
    },
    {
     "file_id": "1jvkLe5ocdLG8-RHmfx69JGiUK4BZ5tTu",
     "timestamp": 1620065109363
    },
    {
     "file_id": "1msPigLz7p7APKgtRyfBG0yqwXuZpD8IF",
     "timestamp": 1619680443846
    },
    {
     "file_id": "1B6n0YZMGNmOAVVYjnsRxL42M7MT3GxOO",
     "timestamp": 1619016741533
    }
   ]
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
